﻿#region

using System.Collections.Generic;
using System.IO;
using System.IO.Compression;
using System.Linq;
using Amazon;
using Amazon.S3;
using Amazon.S3.Model;
using CDNSync.Providers.Model;

#endregion

namespace CDNSync.Providers.Impl
{
    public class AmazonProviderClient : IProviderClient
    {
        private string AwsAccessKey;
        private string AwsSecretAccessKey;
        private AmazonS3 amazonClient;

        #region IProviderClient Members

        public bool Authenticate(string userName, string password)
        {
            AwsAccessKey = userName;
            AwsSecretAccessKey = password;
            amazonClient = AWSClientFactory.CreateAmazonS3Client(userName, password);

            //make a dummy request to validate the credentials are ok 
            try
            {
                amazonClient.GetObject(new GetObjectRequest().WithBucketName("test").WithKey("test"));
            }
            catch (AmazonS3Exception ex)
            {
                if (ex.ErrorCode.Contains("InvalidAccessKeyId") || ex.ErrorCode.Contains("SignatureDoesNotMatch"))
                {
                    return false;
                }
            }

            return true;
        }

        public void Dispose()
        {
            if (amazonClient != null)
            {
                amazonClient.Dispose();
            }
        }

        public bool BucketExists(string bucketName)
        {
            return
                amazonClient.ListBuckets().Buckets.Any(
                    b => b.BucketName.ToLowerInvariant() == bucketName.ToLowerInvariant());
        }

        public CreateBucketResult CreateBucket(string bucketName, BucketRegion region)
        {
            //Clean bucket name
            var s3Region = S3Region.US;

            switch (region)
            {
                case BucketRegion.Singapore:
                    s3Region = S3Region.APS1;
                    break;
                case BucketRegion.USEastCoast:
                    s3Region = S3Region.US;
                    break;
                case BucketRegion.USWestCoast:
                    s3Region = S3Region.SFO;
                    break;
                case BucketRegion.Europe:
                    s3Region = S3Region.EU;
                    break;
            }

            var request = new PutBucketRequest()
                .WithBucketName(bucketName)
                .WithBucketRegion(s3Region);

            var result = new CreateBucketResult();
            try
            {
                var response = amazonClient.PutBucket(request);

                result.AddLogMessage(bucketName + " created in " + region);
            }
            catch (AmazonS3Exception ex)
            {
                result.AddError(ex.ToString());
            }

            return result;
        }

        //public string CreateDistribution(string bucketName, string[] cnames)
        //{
        //    var distConfig = new CloudFrontDistributionConfig()
        //        .WithOrigin(bucketName)
        //        .WithEnabled(true);

        //    if (cnames != null && cnames.Count() > 0)
        //    {
        //        distConfig.WithCNames(cnames);
        //    }

        //    var distRequest = new CreateDistributionRequest().WithDistributionConfig(distConfig);

        //    using (var cloudFrontClient = new AmazonCloudFrontClient(AwsAccessKey, AwsSecretAccessKey))
        //    {
        //        var response = cloudFrontClient.CreateDistribution(distRequest);

        //        return response.Distribution.DomainName;
        //    }
        //}

        //public bool DistributionExists(string bucketName)
        //{
        //    using (var cloudFrontClient = new AmazonCloudFrontClient(AwsAccessKey, AwsSecretAccessKey))
        //    {
        //        var distributions = cloudFrontClient.ListDistributions();
        //        var exists = distributions.Distribution.Any(cd => cd.DistributionConfig.Origin.ToLowerInvariant().StartsWith(bucketName.ToLowerInvariant()));

        //        return exists;
        //    }
        //}

        public UploadFilesResult Upload(IEnumerable<FileUploadRequest> filesToUpload, string bucketName)
        {
            var result = new UploadFilesResult();
            if (filesToUpload == null || filesToUpload.Count() == 0)
            {
                return result;
            }

            foreach (var file in filesToUpload)
            {
                var request = new PutObjectRequest()
                    .WithBucketName(bucketName)
                    .WithCannedACL(S3CannedACL.PublicRead)
                    .WithContentType(file.ContentType)
                    .WithKey(file.TargetKey);

                if (file.Compress)
                {
                    byte[] bufferWrite;


                    MemoryStream ms;


                    using (var fs = new FileStream(file.SourceFilePath, FileMode.Open, FileAccess.Read, FileShare.Read))
                    {
                        bufferWrite = new byte[fs.Length];
                        fs.Read(bufferWrite, 0, bufferWrite.Length);
                        ms = new MemoryStream();
                        using (var gzCompressed = new GZipStream(ms, CompressionMode.Compress, true))
                        {
                            gzCompressed.Write(bufferWrite, 0, bufferWrite.Length);
                            gzCompressed.Close();
                        }

                        fs.Close();
                    }


                    request.InputStream = ms;
                    request.AddHeaders(new System.Collections.Specialized.NameValueCollection {{"Content-Encoding", "gzip"}});
                }
                else
                {
                    request.FilePath = file.SourceFilePath;
                }


                try
                {
                    var response = amazonClient.PutObject(request);
                    result.AddLogMessage(string.Format("{0} has been uploaded to {1} with Key: {2}", file.SourceFilePath, bucketName, file.TargetKey));
                }
                catch (AmazonS3Exception ex)
                {
                    result.AddError(ex.ToString());
                }
            }

            return result;
        }

        #endregion
    }
}